package org.currentcost;


import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.UnsupportedCommOperationException;
import org.currentcost.messages.*;
import org.xml.sax.SAXException;

import java.io.*;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Comparator;

/**
 * Reads 3 history messages then exits.
 */
public class HistoryReader implements MessageConsumer
{
	private final File _outputFile;
	private String _portName;
	private final boolean _cost;
	private final String _sensorId;
	private EnviReader _reader;
	private OutputStreamWriter _writer;
	private int _received;
	private boolean _wroteHeaders;

	public HistoryReader(File outputFile, String portName, boolean cost, String sensorId)
	{
		_outputFile = outputFile;
		_portName = portName;
		_cost = cost;
		_sensorId = sensorId;
	}

	public static void main(String[] args)
	{
		String portName = "COM9";
		File outputFile = null;
		boolean cost = false;
		String sensorId = null;

		for (int i = 0; i < args.length; i++) {
			String arg = args[i];
			if ("-port".equals(arg)) {
				if (i >= args.length) {
					_usage(1);
				}
				i++;
				portName = args[i];
			}
			else if ("-out".equals(arg)) {
				if (i >= args.length) {
					_usage(1);
				}
				i++;
				outputFile = new File(args[i]);
			}
			else if ("-cost".equals(arg)) {
				cost = true;
			}
			else if ("-sensor".equals(arg)) {
				if (i >= args.length) {
					_usage(1);
				}
				i++;
				sensorId = args[i];
			}
			else if ("-?".equals(arg) || "-help".equals(arg) || "-h".equals(arg)) {
				_usage(0);
			}
			else {
				_usage(1);
			}
		}

		HistoryReader testReader = new HistoryReader(outputFile, portName, cost, sensorId);
		try {
			testReader.start();
		}
		catch (Exception e) {
			e.printStackTrace();
			//To change body of catch statement use File | Settings | File Templates.
		}
	}

	private void start() throws UnsupportedCommOperationException, IOException, SAXException, PortInUseException,
	                            NoSuchPortException
	{
		if (_outputFile == null) {
			_writer = new OutputStreamWriter(System.out);
		}
		else {
			_writer = new FileWriter(_outputFile);
		}
		_wroteHeaders = false;
		_writeHeaders(_writer);
		_received = 0;
		_reader = new EnviReader(_portName, this);
		_reader.start();
	}

	private void _writeHeaders(Writer writer) throws IOException
	{
		if (! _cost) {
			writer.append("Sensor Type\tSensor ID\tStart\tEnd\tValue\tUnit\n");
			_wroteHeaders = true;
		}
	}

	private static void _usage(int status)
	{
		System.err.println("Usage: TestReader [ -port <COM port name> ] [ -out <output file> ] [ -cost ] [ -sensor " +
				                   "<sensorId> ]\n");
		System.exit(status);
	}

	@Override
	public void messageReceived(EnviMessage msg)
	{
		if (msg.getType() == EnviMessage.Type.RealTime) {
			// discard
			return;
		}
		try {
			if (_cost) {
				if (msg.getType() == EnviMessage.Type.Hourly) {
					_writeCost(_writer, msg);
				}
			}
			else {
				_writeMessage(_writer, msg);
			}
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		_received++;
		if (_received >= 3) {
			_reader.stop();
			if (_outputFile != null) {
				try {
					_writer.close();
				}
				catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private void _writeCost(OutputStreamWriter writer, EnviMessage msg) throws IOException
	{
		CostMessage costMsg = new CostMessage(msg, _sensorId);

		if (! _wroteHeaders) {
			writer.append("Sensor Type\tSensor ID\tDate\tCost (nor)\tCost (low)\t" + costMsg.getUnit() +" (nor)\t" +
					              costMsg.getUnit() + " (low)\n");
			_wroteHeaders = true;
		}
		CostData[] data = costMsg.getCosts();
		Arrays.sort(data, new Comparator<CostData>()
		{
			@Override
			public int compare(CostData c1, CostData c2)
			{
				return c1.getDate().compareTo(c2.getDate());
			}
		});
		DateFormat dateFormat = DateFormat.getDateInstance();

		for (CostData costData : data) {
			writer.append(costMsg.getSensorType().toString()).append("\t");
			writer.append(costMsg.getSensorId()).append("\t");
			writer.append(dateFormat.format(costData.getDate())).append("\t");
			writer.append(String.valueOf(costData.getNormalCost())).append("\t");
			writer.append(String.valueOf(costData.getLowCost())).append("\t");
			writer.append(String.valueOf(costData.getNormalValue())).append("\t");
			writer.append(String.valueOf(costData.getLowValue())).append("\t");
			writer.append("\n");
		}
		writer.flush();
	}

	private void _writeMessage(Writer writer, EnviMessage msg) throws IOException
	{
		SensorData data = msg.getSensorData();
		SensorData.SensorType type = data.getSensorType();
		ValueData[] dataPoints = data.getDataPoints();
		for (ValueData valueData : dataPoints) {
			if (_sensorId == null || _sensorId.equals(valueData.sensorId)) {
				writer.append(type.toString()).append("\t");
				writer.append(valueData.sensorId).append("\t");
				writer.append(DateFormat.getDateTimeInstance().format(valueData.startDate)).append("\t");
				writer.append(DateFormat.getDateTimeInstance().format(valueData.endDate)).append("\t");
				writer.append(String.valueOf(valueData.value)).append("\t");
				writer.append(valueData.unit.toString()).append("\t");
				writer.append("\n");
				writer.flush();
			}
		}
	}
}
